我们将讨论的最后一个主题是，如何同步图和主机执行。本章中已经涉及到这一点，但现在将研究程序实现这一点的方法。\par

主机同步的第一个方法是:等待队列。队列对象有两个方法，wait和wait\_and\_throw，阻塞执行，直到提交到队列的每个命令组都完成。非常简单的方法，可以处理许多常见的情况。然而，这种方法是粒度非常粗。如果需要更细粒度的同步，需要使用另一种方法。\par

主机同步的另一种方法是对事件进行同步。这比在队列上同步更灵活，因为只允许程序在特定的操作或命令组上同步。这可以通过在事件上调用wait方法或在事件类上调用wait来完成，wait可以接受一个事件组。\par

图8-5和图8-8中使用了不同的方法:主机访问器。主机访问器执行两个功能。首先，使主机上的数据可用。其次，通过在当前访问的图和主机之间定义依赖关系来与主机同步。这可以确保复制回主机的数据是图计算的正确结果。但是，如果缓冲区是由主机内存构造，那么这个原始内存不能保证数值的一致性。\par

注意，主机访问器是阻塞的。在数据可用之前，主机上的执行可能不会在创建主机访问器之后继续。同样，当主机访问器存在并保持其数据可用时，不能在设备上使用缓冲区。一种常见的模式是在C++作用域中创建主机访问器，以便在不再需要主机访问器时释放数据。这是另一种主机同步的方法。\par

DPC++中的某些对象在销毁和调用其析构函数时具有特殊行为。当缓冲区和图像销毁或离开生命周期时，也有特殊的行为。当缓冲区销毁时，将等待所有使用该缓冲区的命令组完成执行。当任何内核或内存操作不再使用缓冲区，运行时必须将数据复制回主机。如果缓冲区使用主机指针初始化，或者主机指针传递给set\_final\_data，则会发生复制。然后，运行时库将复制该缓冲区的数据，并在销毁对象之前更新主机内存。\par

与主机同步的最后一个选项涉及在第7章中描述的一个不常见的特性。回想一下，缓冲区对象的构造函数可选地接受属性列表。创建缓冲区时，传递的属性是use\_mutex。当以这种方式创建缓冲区时，增加了一个要求，即该缓冲区的内存可以与主机程序共享。对该内存的访问由互斥锁控制，当可以安全地访问与缓冲区共享内存时，主机能够获得锁。如果无法获得锁，用户可能需要将内存移动操作排队，以便与主机同步数据。这种用法非常小众，在大多数DPC++应用程序中不太能看到。\par

